package com.jtny.nytb.config.excel.biz.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import com.jtny.component.enums.GenericStatusEnum;
import com.jtny.component.exception.ServiceException;
import com.jtny.component.redis.core.RedisValueService;
import com.jtny.nytb.config.dictionary.dao.TssoConfigDataDictDao;
import com.jtny.nytb.config.dictionary.dao.TssoConfigDataDictionaryDao;
import com.jtny.nytb.config.dictionary.domain.DictionaryDO;
import com.jtny.nytb.config.dictionary.domain.DictionaryDataDO;
import com.jtny.nytb.config.dictionary.dto.DictionaryDTO;
import com.jtny.nytb.config.dictionary.dto.DictionaryDataDTO;
import com.jtny.nytb.config.dictionary.dto.DictionaryInfoDTO;
import com.jtny.nytb.config.dictionary.vo.ExcelDictionaryDataVO;
import com.jtny.nytb.config.dictionary.vo.ExcelDictionaryVO;
import com.jtny.nytb.config.excel.biz.ImportExcelBiz;
import com.jtny.nytb.config.excel.util.ExcelSheetVO;
import com.jtny.nytb.config.measurementtype.dto.MeasurementTypeDTO;
import com.jtny.nytb.config.measurementtype.service.MeasurementTypeService;
import com.jtny.nytb.config.measurementunit.dto.MeasurementUnitDTO;
import com.jtny.nytb.config.unifiedIdentification.dto.UnifiedIdentifierRequestDTO;
import com.jtny.nytb.config.unifiedIdentification.service.UnifiedIdentifier;
import com.jtny.nytb.config.unifiedIdentification.vo.ExcelUnifiedIdentifierVO;
import com.jtny.nytb.config.varible.dao.ConfigGlobalManagementDAO;
import com.jtny.nytb.config.varible.domain.ConfigGlobalManagementDO;
import com.jtny.nytb.config.varible.dto.ConfigGlobalManagementDTO;
import com.jtny.nytb.config.varible.vo.ExcelGlobalParamVO;
import com.jtny.nytb.config.measurementunit.service.MeasurementUnitService;
import com.jtny.nytb.config.measurementunit.vo.ExcelMeasurementUnitVO;
import lombok.AllArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author 智慧能源中心 - 伍天宇
 * @package com.jtny.nytb.config.excel.biz.impl
 * @fileName ImportExcelBizImpl.java
 * @createTime 2023年11月10日 13:41
 * @Copyright© 2023 jtny
 * 江投能源技术研究院 版权所有
 */
@Service
@AllArgsConstructor
public class ImportExcelBizImpl implements ImportExcelBiz {

    @Autowired
    private TssoConfigDataDictDao dictionaryDAO;
    @Autowired
    private TssoConfigDataDictionaryDao dictionaryDataDAO;
    @Autowired
    private ConfigGlobalManagementDAO configGlobalManagementDAO;
    @Autowired
    private MeasurementTypeService measurementTypeService;
    @Resource
    private MeasurementUnitService measurementUnitService;


    private RedisValueService redis;
    public static final String DICTIONARY_INFO_SUFFIX = "dictionary_info_suffix_";
    private static final String CODE_RULE_SUFFIX = "code_rule_suffix_";
    private static final String ALGORITHM_SUFFIX = "algorithm_suffix_";

    /**
     * 导入字典Excel
     *
     * @param map            导入Excel数据
     * @param excelSheetList Excel工作表列表
     */
    @Override
    public Boolean importDictionaryExcel(Map<Class<?>, List<?>> map, List<ExcelSheetVO> excelSheetList) {
        deleteAllRedis();
        List<String> dictionaryNameList = new ArrayList<>();

        for (ExcelSheetVO excelSheetVO : excelSheetList) {
            if (excelSheetVO.getClazz() == ExcelDictionaryVO.class) {
                List<ExcelDictionaryVO> excelDictionaryVOList = (List<ExcelDictionaryVO>) map.get(excelSheetVO.getClazz());
                List<ExcelDictionaryVO> excelDictionaryVOS = cleanDictionaryByName(excelDictionaryVOList);
                for (ExcelDictionaryVO excelDictionaryVO : excelDictionaryVOS) {
                    dictionaryNameList.add(excelDictionaryVO.getName());
                    setRedisDictionary(excelDictionaryVO);
                }
            }
            if (excelSheetVO.getClazz() == ExcelDictionaryDataVO.class) {
                List<ExcelDictionaryDataVO> excelDictionaryDataVOList = (List<ExcelDictionaryDataVO>) map.get(excelSheetVO.getClazz());
                Map<String, List<ExcelDictionaryDataVO>> tempMap = excelDictionaryDataVOList.stream()
                        .collect(Collectors.groupingBy(ExcelDictionaryDataVO::getDictionaryName));
                for (String dictionaryName : tempMap.keySet()) {
                    setRedisDictionaryData(dictionaryName, tempMap.get(dictionaryName));
                }
            }
        }
        if (ObjectUtil.isNotEmpty(dictionaryNameList)) {
            List<DictionaryInfoDTO> toSaveList = getRedisAllByKey(dictionaryNameList, DICTIONARY_INFO_SUFFIX, DictionaryInfoDTO.class);
            //数据库操作
            saveBatchDictionary(toSaveList);
        }
        deleteAllRedis();
        return Boolean.TRUE;
    }

    /**
     * 导入全局值 Excel
     *
     * @param globalParamList 全局值列表
     * @return {@link Boolean}
     */
    @Override
    public Boolean importGlobalValueExcel(List<ExcelGlobalParamVO> globalParamList) {
        List<ConfigGlobalManagementDTO> configGlobalManagementList = globalParamList.stream()
                .map(ExcelGlobalParamVO::toBuildDto)
                .collect(Collectors.toList());
        //configGlobalManagementClient数据库操作
        return saveBatch(configGlobalManagementList);
    }


    /**
     * 设置 Redis 字典数据
     *
     * @param dictionaryName          字典名称
     * @param excelDictionaryDataList Excel 字典数据列表
     */
    private void setRedisDictionaryData(String dictionaryName, List<ExcelDictionaryDataVO> excelDictionaryDataList) {
        DictionaryInfoDTO redisDictionary = getRedisByKey(DICTIONARY_INFO_SUFFIX, dictionaryName, DictionaryInfoDTO.class);
        if (ObjectUtil.isNotEmpty(redisDictionary)) {
            List<DictionaryDataDTO> tempList = new ArrayList<>();
            for (int i = 0; i < excelDictionaryDataList.size(); i++) {
                ExcelDictionaryDataVO excelDictionaryDataVO = excelDictionaryDataList.get(i);
                DictionaryDataDTO dictionaryDataDTO = excelDictionaryDataVO.toDictionaryDataDTO(i + 1);
                tempList.add(dictionaryDataDTO);
            }
            redisDictionary.setDictionaryDataList(tempList);
            setRedisDictionaryDTO(redisDictionary);
        }
    }


    /**
     * 按名称清理词典
     *
     * @param excelDictionaryVOList Excel 词典 Volist
     * @return {@link List}<{@link ExcelDictionaryVO}>
     */
    private List<ExcelDictionaryVO> cleanDictionaryByName(List<ExcelDictionaryVO> excelDictionaryVOList) {
        List<String> nameList = excelDictionaryVOList.stream().map(ExcelDictionaryVO::getName).collect(Collectors.toList());
        //数据库操作
        List<String> existNameList = existDictionaryByName(nameList);
        return excelDictionaryVOList.stream().filter(excelDictionaryVO -> !existNameList.contains(excelDictionaryVO.getName())).collect(Collectors.toList());
    }

    /**
     * 通过 Redis 所有的
     *
     * @param keyList   nameList
     * @param keySuffix 前缀
     * @param clazz     克拉兹
     * @return {@link List}<{@link T}>
     */
    private <T> List<T> getRedisAllByKey(List<String> keyList, String keySuffix, Class<T> clazz) {
        List<String> collect = keyList.stream().map(str -> keySuffix + str).collect(Collectors.toList());
        List<String> stringList = redis.get(collect);
        List<T> result = new ArrayList<>();
        if (ObjectUtil.isEmpty(stringList)) {
            BeanUtils.copyProperties(clazz, result);
            return result;
        }
        for (String redisByKey : stringList) {
            result.add(JSON.parseObject(redisByKey, clazz));
        }
        return result;
    }


    private void setRedisByKey(String key, String value) {
        if (StrUtil.isNotBlank(value)) {
            redis.set(key, value, 1L, TimeUnit.HOURS);
        }
    }

    private void setRedisDictionary(ExcelDictionaryVO excelDictionaryVO) {
        DictionaryDTO dictionaryDTO = excelDictionaryVO.toDictionaryDTO();
        DictionaryInfoDTO dictionaryInfoDTO = new DictionaryInfoDTO();
        dictionaryInfoDTO.setDictionary(dictionaryDTO);
        setRedisDictionaryDTO(dictionaryInfoDTO);
    }

    private void setRedisDictionaryDTO(DictionaryInfoDTO dictionaryInfoDTO) {
        setRedisByKey(DICTIONARY_INFO_SUFFIX + dictionaryInfoDTO.getDictionary().getName(), JSON.toJSONString(dictionaryInfoDTO));
    }

    @Override
    public Boolean importMeasurementUnitExcel(List<ExcelMeasurementUnitVO> measurementUnitList) {
        List<String> measurementTypeNameList = measurementUnitList.stream()
                .map(ExcelMeasurementUnitVO::getTypeName)
                .collect(Collectors.toList());
        Map<String, MeasurementTypeDTO> map = measurementTypeService.mapMeasurementTypeByName(measurementTypeNameList);

        List<MeasurementUnitDTO> measurementUnitDTOList = measurementUnitList.stream()
                .map(item -> {
                    MeasurementUnitDTO buildDto = item.toBuildDto();
                    MeasurementTypeDTO orDefault = map.getOrDefault(item.getTypeName(), new MeasurementTypeDTO());
                    buildDto.setTypeId(orDefault.getId());
                    return buildDto;
                })
                .collect(Collectors.toList());
        return measurementUnitService.saveBatch(measurementUnitDTOList);
    }



    /**
     * 通过密钥获取 Redis
     *
     * @param suffix 后缀
     * @param key    我？
     * @param clazz  克拉兹
     * @return {@link T}
     */
    private <T> T getRedisByKey(String suffix, String key, Class<T> clazz) {
        String redisByKey = getRedisByKey(suffix + key);
        return JSON.parseObject(redisByKey, clazz);
    }

    private String getRedisByKey(String key) {
        return redis.get(key);
    }

    private void deleteAllRedis() {
        redis.deleteLike(DICTIONARY_INFO_SUFFIX);
        redis.deleteLike(CODE_RULE_SUFFIX);
        redis.deleteLike(ALGORITHM_SUFFIX);
    }

    public Boolean saveBatchDictionary(List<DictionaryInfoDTO> dictionaryInfoList) {
        for (DictionaryInfoDTO dictionaryInfoDTO : dictionaryInfoList) {
            DictionaryDTO save = save(dictionaryInfoDTO.getDictionary());
            Long id = save.getId();
            if (CollUtil.isNotEmpty(dictionaryInfoDTO.getDictionaryDataList())) {
                List<DictionaryDataDO> collect = dictionaryInfoDTO.getDictionaryDataList().stream().map(item -> {
                    DictionaryDataDO dictionaryDataDO = com.jtny.component.util.BeanUtils.copyToObject(item, DictionaryDataDO.class);
                    dictionaryDataDO.setDictId(id);
                    return dictionaryDataDO;
                }).collect(Collectors.toList());
                dictionaryDataDAO.insertBatch(collect);
            }
        }
        return Boolean.TRUE;
    }

    public DictionaryDTO save(DictionaryDTO dictionaryDTO) throws ServiceException {

        // 将DTO对象的属性复制给DO对象
        DictionaryDO dictionaryDO = com.jtny.component.util.BeanUtils.copyToObject(dictionaryDTO, DictionaryDO.class);
        // 保存操作
        dictionaryDAO.insert(dictionaryDO);
        // 将id设置给DTO对象
        dictionaryDTO.setId(dictionaryDO.getId());

        return dictionaryDTO;
    }

    /**
     * 按名称存在字典
     *
     * @param nameList 名称列表
     * @return {@link List}<{@link String}>
     */

    public List<String> existDictionaryByName(List<String> nameList) {
        if (CollUtil.isNotEmpty(nameList)) {
            LambdaQueryWrapper<DictionaryDO> wrapper = Wrappers.<DictionaryDO>lambdaQuery()
                    .in(DictionaryDO::getName, nameList)
                    .ne(DictionaryDO::getStatus, GenericStatusEnum.DELETED.getValue());
            List<DictionaryDO> dictionaryList = dictionaryDAO.selectList(wrapper);
            return dictionaryList.stream().map(DictionaryDO::getName).collect(Collectors.toList());
        }
        return CollUtil.newArrayList();
    }

    /**
     * 批量保存
     *
     * @param configGlobalManagementList 配置全局管理列表
     * @return {@link Boolean}
     */
    @Transactional(rollbackFor = Exception.class)
    public Boolean saveBatch(List<ConfigGlobalManagementDTO> configGlobalManagementList) {
        if (CollUtil.isNotEmpty(configGlobalManagementList)) {

            List<ConfigGlobalManagementDO> toSaveList = configGlobalManagementList.stream().map(item -> {
                ConfigGlobalManagementDO configGlobalManagementDO = com.jtny.component.util.BeanUtils.copyToObject(item, ConfigGlobalManagementDO.class);
                String code = createCode();
                configGlobalManagementDO.setCode(code);
                return configGlobalManagementDO;
            }).collect(Collectors.toList());
            return SqlHelper.retBool(configGlobalManagementDAO.insertBatch(toSaveList));
        }
        return Boolean.FALSE;
    }

    private String createCode() {
        List<ConfigGlobalManagementDO> configGlobalManagementDOS = configGlobalManagementDAO.selectList(null);
        //获取所有Code
        List<String> collect = configGlobalManagementDOS.stream().map(ConfigGlobalManagementDO::getCode).collect(Collectors.toList());
        if (collect!=null) {
            List<Integer> integerList = configGlobalManagementDOS.stream()
                    .map(ConfigGlobalManagementDO::getCode)
                    .map(code -> {
                        if (code != null && code.length() >= 5) {
                            return Integer.parseInt(code.substring(code.length() - 5));
                        } else {
                            return null; // 或者根据需要处理长度小于5的情况
                        }
                    })
                    .filter(Objects::nonNull)
                    .collect(Collectors.toList());
            Optional<Integer> max = integerList.stream().max(Integer::compareTo);
            String integer = max.get().toString();
            //保存，新进来的Code加1
            integer=integer+1;

            String stringCode="";
            if (integer.length()!=5){
                int i1 = 5 - integer.length();
                for (int i=0;i<i1;i++){
                    stringCode=stringCode+"0";
                }
            }
            return "G"+stringCode;
        }
        return "G00001";
    }
}
